package com.parking.mgr.useraccount.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.parking.mgr.common.cache.RedisCache;
import com.parking.mgr.common.constant.CommonConstant;
import com.parking.mgr.common.enums.CommonStatusEnum;
import com.parking.mgr.common.exception.ServiceException;
import com.parking.mgr.common.exception.enums.CommonExceptionEnum;
import com.parking.mgr.common.exception.enums.DeleteUpdateExceptionEnums;
import com.parking.mgr.common.factory.TreeBuildFactory;
import com.parking.mgr.common.pojo.base.entity.BaseEntity;
import com.parking.mgr.common.util.IdUtils;
import com.parking.mgr.common.util.MessageUtils;
import com.parking.mgr.useraccount.enums.MenuEnterStateEnum;
import com.parking.mgr.useraccount.facede.LoginServiceFacede;
import com.parking.mgr.useraccount.model.entity.BasicMenuEntity;
import com.parking.mgr.useraccount.model.mapper.BasicMenuMapper;
import com.parking.mgr.useraccount.model.mapstruct.BasicMenuMapStruct;
import com.parking.mgr.useraccount.model.param.BasicMenuParam;
import com.parking.mgr.useraccount.model.vo.BasicMenuVO;
import com.parking.mgr.useraccount.service.BasicMenuService;
import lombok.extern.log4j.Log4j2;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @ClassName BasicMenuServiceImpl
 * @Description TODO
 * @Auther: zhijianpu
 * @Date: 2023/5/19
 */
@Log4j2
@Service
public class BasicMenuServiceImpl extends ServiceImpl<BasicMenuMapper, BasicMenuEntity> implements BasicMenuService {

    @Resource
    private BasicMenuMapper basicMenuMapper;

    @Resource
    private BasicMenuMapStruct basicMenuMapStruct;

    @Resource
    private LoginServiceFacede loginServiceFacede;

    @Resource
    private RedisCache redisCache;


    @Override
    public List<BasicMenuVO> list(BasicMenuParam basicMenuParam, HttpServletRequest request) {
        LambdaQueryWrapper<BasicMenuEntity> queryWrapper = new LambdaQueryWrapper<>();
        if (ObjectUtil.isNotNull(basicMenuParam)) {
            // 根据菜单名称模糊查询
            if (ObjectUtil.isNotEmpty(basicMenuParam.getFName())) {
                queryWrapper.like(BasicMenuEntity::getFName, basicMenuParam.getFName());
            }
        }
        // 根据排序升序排列，序号越小越在前
        queryWrapper.orderByAsc(BasicMenuEntity::getFSortNumber);
        List<BasicMenuEntity> basicMenuList = this.list(queryWrapper);
        // 将结果集处理成树
        List<BasicMenuEntity> menuTree = new TreeBuildFactory<BasicMenuEntity>().build(basicMenuList);
        List<BasicMenuVO> menuVOTrees = basicMenuMapStruct.entity2VO(menuTree);
        return menuVOTrees;
    }

    @Override
    public List<BasicMenuVO> listEnable(BasicMenuParam basicMenuParam, HttpServletRequest request) {
        LambdaQueryWrapper<BasicMenuEntity> queryWrapper = new LambdaQueryWrapper<>();
        if (ObjectUtil.isNotNull(basicMenuParam)) {
            // 根据菜单名称模糊查询
            if (ObjectUtil.isNotEmpty(basicMenuParam.getFName())) {
                queryWrapper.like(BasicMenuEntity::getFName, basicMenuParam.getFName());
            }
        }
        queryWrapper.eq(BasicMenuEntity::getFEnableState, CommonStatusEnum.ENABLE.getCode());
        // 根据排序升序排列，序号越小越在前
        queryWrapper.orderByAsc(BasicMenuEntity::getFSortNumber);
        List<BasicMenuEntity> basicMenuList = this.list(queryWrapper);
        // 将结果集处理成树
        List<BasicMenuEntity> menuTree = new TreeBuildFactory<BasicMenuEntity>().build(basicMenuList);
        List<BasicMenuVO> menuVOTrees = basicMenuMapStruct.entity2VO(menuTree);
        return menuVOTrees;
    }

    @Override
    public List<BasicMenuVO> listAll(HttpServletRequest request) {
        LambdaQueryWrapper<BasicMenuEntity> queryWrapper = new LambdaQueryWrapper<>();
        // 根据排序升序排列，序号越小越在前
        queryWrapper.orderByAsc(BasicMenuEntity::getFSortNumber);
        return basicMenuMapStruct.entity2VO(this.list(queryWrapper));
    }

    @Override
    public List<BasicMenuVO> treeMenuE(HttpServletRequest request) {
        // 获取组件系统ID
        QueryWrapper queryWrapper = new QueryWrapper();
        log.info("获取功能菜单树，分为登录和非登录状态，判断登录状态");
        boolean isLoginAuth = loginServiceFacede.isLoginAuth(request);
        log.info("用户登录状态: " + isLoginAuth);

        queryWrapper.eq("f_enter_state", MenuEnterStateEnum.ENTER.getCode());
        // 根据排序升序排列，序号越小越在前
        queryWrapper.orderByAsc("f_sort_number");

        List<BasicMenuEntity> basicMenuList;
        List<BasicMenuEntity> newbasicMenuList;

        if (!isLoginAuth) {

            basicMenuList = basicMenuMapper.selectNoUserTreeMenuE(queryWrapper);
        } else {
            String passportId = loginServiceFacede.getPassportIdByToken(request);
            queryWrapper.eq("fk_user_passport_id", passportId);

            basicMenuList = basicMenuMapper.selectTreeMenuE(queryWrapper);
        }

        // 用户已经登录，需要根据角色显示该角色下的菜单数据
        // 获取用户的账户ID

//        // 根据用户账户ID，获取所属用户角色ID，角色ID可能存在多个
//        List<String> userRoleIds = basicRoleServiceFacede.getRoleUserList(passportId);
//        // 根据角色ID，获取菜单ID，用户存在多个角色，会出现菜单数据重复，把菜单ID放入到Set集合中去重
//        Set roleMenuIdsSet = new HashSet();
//        if (CollectionUtil.isNotEmpty(userRoleIds)) {
//            // 获取角色ID
//            for (String roleIds : userRoleIds) {
//                // 根据角色ID，获取菜单ID集合
//                CollectionUtil.addAll(roleMenuIdsSet, basicRoleServiceFacede.getRoleMenuListByRoleId(roleIds));
//            }
//        }


        //queryWrapper.eq("fk_basic_cmp_sys_id", request.getHeader(CommonConstant.CMP_SYS_ID));

        // 菜单数据去重
        newbasicMenuList = basicMenuList.stream().distinct().collect(Collectors.toList());

        // 将结果集处理成树
        List<BasicMenuEntity> menuTree = new TreeBuildFactory<BasicMenuEntity>().build(newbasicMenuList);
        List<BasicMenuVO> menuVOTrees = basicMenuMapStruct.entity2VO(menuTree);
        return menuVOTrees;
    }

    @Override
    public void add(BasicMenuParam basicMenuParam, HttpServletRequest request) {
        // 校验参数
        checkParam(basicMenuParam, false);

        log.info("获取组建系统ID");
        BasicMenuEntity basicMenuEntity = new BasicMenuEntity();
        BeanUtil.copyProperties(basicMenuParam, basicMenuEntity);
        //String fKeyParam = basicMenuParam.getFKey();
        // 设置启用状态
        basicMenuEntity.setFEnableState(CommonStatusEnum.ENABLE.getCode());
        basicMenuEntity.setId(IdUtils.getId());
        // 设置组建系统ID
        // basicMenuEntity.setFkBasicCmpSysId(cmpSysId);

        this.save(basicMenuEntity);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void delete(Collection<String> ids, HttpServletRequest request) {
        for (String id : ids) {
            BasicMenuEntity basicMenuEntity = this.basicMenuMapper.selectById(id);
            if (ObjectUtil.isNull(basicMenuEntity)) {
                throw new ServiceException(CommonExceptionEnum.DATA_NOT_EXIST.getMessage());
            }
            if (ObjectUtil.equals(CommonConstant.CAN_DELETE, basicMenuEntity.getFCanDelete())) {
                Set<String> childList = this.getChildIdListById(Collections.singletonList(id));
                if (childList.isEmpty()) {
                    this.removeById(id);
                } else {
                    throw new ServiceException(DeleteUpdateExceptionEnums.CAN_NOT_DELETE_EXIST_CHILD_NODE.getMessage());
                }
            } else {
                throw new ServiceException(DeleteUpdateExceptionEnums.CAN_NOT_DELETE.getMessage());
            }
            /*LambdaQueryWrapper<BasicMenuEntity> basicMenuEntityLambdaQueryWrapper =
                    new LambdaQueryWrapper<BasicMenuEntity>().in(BasicMenuEntity::getId, childList);
            // 该字段已经被删除
            //.eq(BasicMenuEntity::getFkBasicCmpSysId, request.getHeader(CommonConstant.CMP_SYS_ID));
            basicMenuMapper.delete(basicMenuEntityLambdaQueryWrapper);*/
        }

    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void edit(BasicMenuParam basicMenuParam, HttpServletRequest request) {
        // 校验参数
        checkParam(basicMenuParam, true);
        // 获取修改的菜单的旧数据
//        BasicMenuEntity currentMenu = this.queryBasicMenu(basicMenuParam);
        BasicMenuEntity basicMenuEntity = this.basicMenuMapper.selectById(basicMenuParam.getId());
        if (ObjectUtil.isNull(basicMenuEntity)) {
            throw new ServiceException(CommonExceptionEnum.DATA_NOT_EXIST.getMessage());

        }
        if (ObjectUtil.equals(CommonConstant.CAN_UPDATE, basicMenuEntity.getFCanUpdate())) {
            // 拷贝参数到实体中
            BeanUtil.copyProperties(basicMenuParam, basicMenuEntity);
            this.updateById(basicMenuEntity);
        } else {
            throw new ServiceException(DeleteUpdateExceptionEnums.CAN_NOT_UPDATE.getMessage());
        }
    }

    @Override
    public void move(String currentId, String newId) {
        // 获取当前菜单对象
        BasicMenuEntity currentMenu = this.getById(currentId);
        // 获取当前节点所有的子节点
        Set<String> childIdListById = this.getChildIdListById(Collections.singletonList(currentId));
        if (ObjectUtil.isNotEmpty(childIdListById)) {
            if (childIdListById.contains(newId)) {
                throw new ServiceException(CommonExceptionEnum.CAN_NOT_MOVE_CURRENT_NODE.getMessage());
            }
        }

        // 获取当前目录的父节点
        String parentId = currentMenu.getFkParentId();
        if (parentId.equals(newId)) {
            throw new ServiceException(CommonExceptionEnum.CAN_NOT_MOVE_CURRENT_NODE.getMessage());
        }

        if (currentId.equals(newId)) {
            throw new ServiceException(CommonExceptionEnum.CAN_NOT_MOVE_CURRENT_NODE.getMessage());
        }

        currentMenu.setFkParentId(newId);
        this.updateById(currentMenu);
    }

    @Override
    public List<String> getMenuUrlByMenuIds(List<String> roleMenuIds) {
        LambdaQueryWrapper<BasicMenuEntity> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.in(BasicMenuEntity::getId, roleMenuIds).eq(BaseEntity::getFEnableState, CommonStatusEnum.ENABLE.getCode());
        List<BasicMenuEntity> menuEntityList = this.list(queryWrapper);
        if (CollectionUtil.isEmpty(menuEntityList)) {
            throw new ServiceException(CommonExceptionEnum.DATA_NOT_EXIST.getMessage());
        }

        List<String> menuUrlList = new ArrayList<>(menuEntityList.size());
        for (BasicMenuEntity menuEntity : menuEntityList) {
            menuUrlList.add(menuEntity.getFUrl());
        }
        return menuUrlList;
    }


    @Override
    public List<BasicMenuVO> acceMenuETreeByCache(HttpServletRequest request) {
        // 获取组件系统ID
        List<BasicMenuVO> menuList = CollUtil.newArrayList();
        // 获取缓存key
        String cacheKey = CommonConstant.USER_ACCOUNT_KEY + request.getRequestURI();
        if (redisCache.hasKey(cacheKey)) {
            menuList = redisCache.getCacheList(cacheKey);
        } else {
            QueryWrapper queryWrapper = new QueryWrapper();
            queryWrapper.eq("f_enter_state", MenuEnterStateEnum.ENTER.getCode());
            // 根据排序升序排列，序号越小越在前
            queryWrapper.orderByAsc("f_sort_number");

            List<BasicMenuEntity> menuEntityList = basicMenuMapper.selectNoUserTreeMenuE(queryWrapper);
            List<BasicMenuEntity> newMenuEntityList = menuEntityList.stream().distinct().collect(Collectors.toList());
            List<BasicMenuEntity> menuTree = new TreeBuildFactory<BasicMenuEntity>().build(newMenuEntityList);
            menuList = basicMenuMapStruct.entity2VO(menuTree);
            redisCache.setCacheList(cacheKey, menuList);
        }

        return menuList;
    }

    @Override
    public List<BasicMenuVO> acceMenuEListByCache(HttpServletRequest request) {
        List<BasicMenuVO> menuList = CollUtil.newArrayList();
        // 获取缓存key
        String cacheKey = CommonConstant.USER_ACCOUNT_KEY + request.getRequestURI();
        if (redisCache.hasKey(cacheKey)) {
            menuList = redisCache.getCacheList(cacheKey);
        } else {
            QueryWrapper queryWrapper = new QueryWrapper();
            queryWrapper.eq("f_enter_state", MenuEnterStateEnum.ENTER.getCode());
            // 根据排序升序排列，序号越小越在前
            queryWrapper.orderByAsc("f_sort_number");

            List<BasicMenuEntity> menuEntityList = basicMenuMapper.selectNoUserTreeMenuE(queryWrapper);
            List<BasicMenuEntity> newMenuEntityList = menuEntityList.stream().distinct().collect(Collectors.toList());
            menuList = basicMenuMapStruct.entity2VO(newMenuEntityList);
            redisCache.setCacheList(cacheKey, menuList);
        }

        return menuList;
    }

    @Override
    public List<BasicMenuVO> acceMenuFListByCache(HttpServletRequest request) {
        List<BasicMenuVO> menuList = CollUtil.newArrayList();
        // 获取缓存key
        String cacheKey = CommonConstant.USER_ACCOUNT_KEY + request.getRequestURI();
        if (redisCache.hasKey(cacheKey)) {
            menuList = redisCache.getCacheList(cacheKey);
        } else {
            QueryWrapper queryWrapper = new QueryWrapper();
            // 根据排序升序排列，序号越小越在前
            queryWrapper.orderByAsc("f_sort_number");

            List<BasicMenuEntity> menuEntityList = basicMenuMapper.selectNoUserTreeMenuE(queryWrapper);
            List<BasicMenuEntity> newMenuEntityList = menuEntityList.stream().distinct().collect(Collectors.toList());
            menuList = basicMenuMapStruct.entity2VO(newMenuEntityList);
            redisCache.setCacheList(cacheKey, menuList);
        }

        return menuList;
    }


    /**
     * 校验参数
     *
     * @param basicMenuParam
     * @param isExcludeSelf
     */
    private void checkParam(BasicMenuParam basicMenuParam, boolean isExcludeSelf) {
        // 是否是入口功能菜单
        String enterState = basicMenuParam.getFEnterState();

        // url
        String url = basicMenuParam.getFUrl();

        // 判断是否是功能入口菜单
        if (enterState.equals("1")) {
            if (ObjectUtil.isEmpty(url)) {
                throw new ServiceException(MessageUtils.message(CommonExceptionEnum.I18N_MESSAGE_MENU_ROUTER_EMPTY.getMessage(),
                        CommonExceptionEnum.I18N_MESSAGE_MENU_ROUTER_EMPTY.getMessage()));
            }
        } else {
            if (ObjectUtil.isEmpty(url)) {
                throw new ServiceException(MessageUtils.message(CommonExceptionEnum.I18N_MESSAGE_MENU_ROUTER_EMPTY.getMessage(),
                        CommonExceptionEnum.I18N_MESSAGE_MENU_ROUTER_EMPTY.getMessage()));
            }
        }

        // 如果是编辑菜单时，parentId 和 id 不能一致，一致会导致无限递归
        if (isExcludeSelf) {
            if (basicMenuParam.getId().equals(basicMenuParam.getFkParentId())) {
                throw new ServiceException(MessageUtils.message(CommonExceptionEnum.I18N_MESSAGE_PARENT_ID_CAN_NOT_EQ_CURRENT_ID.getMessage(),
                        CommonExceptionEnum.I18N_MESSAGE_PARENT_ID_CAN_NOT_EQ_CURRENT_ID.getMessage()));
            }

            // 如果是编辑，父id不能为自己的子节点
            Set<String> childIdListById = this.getChildIdListById(Collections.singletonList(basicMenuParam.getId()));
            if (ObjectUtil.isNotEmpty(childIdListById)) {
                if (childIdListById.contains(basicMenuParam.getFkParentId())) {
                    throw new ServiceException(MessageUtils.message(CommonExceptionEnum.I18N_MESSAGE_PARENT_ID_CAN_NOT_EQ_CHILD_ID.getMessage(),
                            CommonExceptionEnum.I18N_MESSAGE_PARENT_ID_CAN_NOT_EQ_CHILD_ID.getMessage()));
                }
            }
        }

//        String id = basicMenuParam.getId();
//        String key = basicMenuParam.getFKey();
//
//        LambdaQueryWrapper<BasicMenuEntity> queryWrapperByKey = new LambdaQueryWrapper<>();
//        queryWrapperByKey.eq(BasicMenuEntity::getFKey, key)
//                .ne(BasicMenuEntity::getFEnableState, CommonStatusEnum.DISABLE.getCode());
//
//        if (isExcludeSelf) {
//            queryWrapperByKey.ne(BasicMenuEntity::getId, id);
//        }
//        int countByKey = this.count(queryWrapperByKey);
//
//        if (countByKey >= 1) {
//            throw new ServiceException(SysMenuExceptionEnum.MENU_CODE_REPEAT);
//        }
    }

    /**
     * 根据节点ID获取所有子节点ID集合
     *
     * @param parentIds
     * @return
     */
    private Set<String> getChildIdListById(Collection<String> parentIds) {
        Set<String> acids = new HashSet<>();
        Collection<String> dpids = parentIds;
        do {
            Set<String> cids = this.list(new LambdaQueryWrapper<BasicMenuEntity>().
                            in(BasicMenuEntity::getFkParentId, dpids)).
                    stream().map(BasicMenuEntity::getId)
                    .collect(Collectors.toSet());
            if (cids.isEmpty()) {
                return acids;
            }
            acids.addAll(cids);
            dpids = cids;
        } while (true);
    }

    /**
     * 获取系统菜单
     *
     * @param basicMenuParam
     * @return
     */
    private BasicMenuEntity queryBasicMenu(BasicMenuParam basicMenuParam) {
        BasicMenuEntity basicMenuEntity = this.getById(basicMenuParam.getId());
        if (ObjectUtil.isNull(basicMenuEntity)) {
            throw new ServiceException(MessageUtils.message(CommonExceptionEnum.I18N_MESSAGE_DATA_NOT_EXIST.getMessage(),
                    CommonExceptionEnum.I18N_MESSAGE_DATA_NOT_EXIST.getMessage()));
        }
        return basicMenuEntity;
    }

}
